package netty.proto;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import student.Message;

public class NettyService {
    public static void main(String[] args) {
        /**
         * 创建 bossGroup 和 workGroup 两个线程组
         * bossGroup 只处理连接请求，而 workGroup 负责真正客户端业务处理
         * 两个都会无线循环
         * 其中含有子线程 NioEventLoop
         * 其默认线程数为 cpu核数 * 2 -> NettyRuntime.availableProcessors() * 2
         */
        EventLoopGroup bossGroup = new NioEventLoopGroup(2);
        EventLoopGroup workGroup = new NioEventLoopGroup(3);
        try {
            // 创建服务器启动对象
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            // 设置参数
            serverBootstrap.group(bossGroup, workGroup) // 设置两个线程组
                    .channel(NioServerSocketChannel.class)  // 使用 NioServerSocketChannel 作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列得到的连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 设置保持活动连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() { // handler 对应 bossGroup, childHandler 对应 workerGroup
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast("decoder", new ProtobufDecoder(Message.getDefaultInstance()))
                                    .addLast(new NettyServerHandler())
                                    ;
                            ; // 为 pipeline 添加 handler
                        }
                    });
            System.out.println("服务器 is ready...");
            // 绑定一个端口并同步
            ChannelFuture channelFuture = serverBootstrap.bind(7777).sync();
            // 对关闭通道进行监听
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭线程组
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}
